use cosmwasm_std::{HumanAddr, Uint128};
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};

use crate::state::ConfigInfo;
use hermit_toolkit_hmip21::asset::AssetInfo;

#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub struct InstantiateMsg {
    pub owner: Option<HumanAddr>,
    pub lp_token_code_id: u64,
    pub lp_token_code_hash: String,
    pub protocol_fee_recipient: HumanAddr,
    pub dao_fee_recipient: HumanAddr,
    pub protocol_fee_percent: u64,
    pub dao_fee_percent: u64,
    pub lp_fee_percent: u64,
}

#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum ExecuteMsg {
    AddPool {
        token_a_asset: AssetInfo,
        token_b_asset: AssetInfo,
    },
    Register {
        token_a_address: HumanAddr,
        token_b_address: HumanAddr,
    },
    AddLiquidity {
        token_a_address: HumanAddr,
        token_b_address: HumanAddr,
        token_a_amount: Uint128,
        min_liquidity: Uint128,
        max_token_b: Uint128,
    },
    RemoveLiquidity {
        token_a_address: HumanAddr,
        token_b_address: HumanAddr,
        amount: Uint128,
        min_token_a: Uint128,
        min_token_b: Uint128,
    },
    Swap {
        token_a_address: HumanAddr,
        token_b_address: HumanAddr,
        input_amount: Uint128,
        min_output: Uint128,
    },
    SwapAndSendTo {
        token_a_address: HumanAddr,
        token_b_address: HumanAddr,
        input_amount: Uint128,
        recipient: HumanAddr,
        min_output: Uint128,
    },
    UpdateConfig {
        config: ConfigInfo,
    },
    SetTrFees {
        token_address: HumanAddr,
        in_fees: u64,
        out_fees: u64,
    },
    CollectTransferFees {
        user_address: HumanAddr,
        token_address: HumanAddr,
        transfer_fees: Uint128,
    },
}

#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum QueryMsg {
    Config {},
    PoolInfo {
        token_a_address: HumanAddr,
        token_b_address: HumanAddr,
    },
    QueryTokenAForTokenBPrice {
        token_a_address: HumanAddr,
        token_b_address: HumanAddr,
        token_a_amount: Uint128,
    },
    QueryTokenBForTokenAPrice {
        token_a_address: HumanAddr,
        token_b_address: HumanAddr,
        token_b_amount: Uint128,
    },
    QueryTrFees {
        token_address: HumanAddr,
    },
    QueryPairTrFees {
        token_a_address: HumanAddr,
        token_b_address: HumanAddr,
    },
    Pools {},
}

#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
pub struct TokenAForTokenBPriceResponse {
    pub token_b_amount: Uint128,
}

#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
pub struct TokenBForTokenAPriceResponse {
    pub token_a_amount: Uint128,
}

#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
pub struct Token {
    pub reserve: Uint128,
    pub asset: AssetInfo,
}

#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
pub enum TokenSelect {
    TokenA,
    TokenB,
}

#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub struct PoolInfoResponse {
    pub token_a_asset: AssetInfo,
    pub token_a_reserve: Uint128,
    pub token_b_asset: AssetInfo,
    pub token_b_reserve: Uint128,
    pub lp_token_supply: Uint128,
    pub lp_token_asset: AssetInfo,
    pub creator: HumanAddr,
    pub create_block: u64,
}
